package com.tokenplus.thai.utils.analytics.util

import android.annotation.SuppressLint
import android.app.AppOpsManager
import android.app.Application
import android.app.usage.UsageEvents
import android.app.usage.UsageStats
import android.app.usage.UsageStatsManager
import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.Process
import android.provider.Settings
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import com.google.gson.Gson
import com.tokenplus.thai.anetwork.ApiUrl
import com.tokenplus.thai.utils.AppConfigUtil
import com.tokenplus.thai.utils.analytics.bean.ParamConfigurationStats
import com.tokenplus.thai.utils.analytics.bean.ParamEventStats
import com.tokenplus.thai.utils.analytics.bean.ParamUsageStats
import com.tokenplus.thai.utils.analytics.bean.ParamUsageStatsS2S
import com.tokenplus.thai.utils.analytics.extend.toGZipString
import com.tokenplus.thai.utils.analytics.http.HttpHelper
import com.tokenplus.thai.utils.analytics.timezone.TimeZoneUtil
import kotlinx.coroutines.*
import java.lang.reflect.Field


object UsageStatsUtil {

    /** 创建job */
    private val mJob = Job()

    /** 创建协程作用域 */
    private val mScope = CoroutineScope(mJob)

    /** 查询天数，默认7天*/
    private var mFetchDays: Int = 7

    /** 1天的毫秒数，1000 * 60 * 60 * 24 */
    private const val DIFFER_DAY_TIME_MILLIS = 86400000L

    /**
     * 初始化
     *
     * @param fetchDays 初始化数据抓取天数
     */
    fun init(fetchDays: Int = 7) {
        mFetchDays = fetchDays
    }

    /**
     * 判断是否拥有权限
     * 若拥有权限，则自动上传数据
     * 若没有权限，直接回调
     *
     * @param context Application
     * @param permissionGrantListener 需要手动授权回调
     */
    fun checkAppUsagePermission(context: Application, permissionGrantListener: (Boolean) -> Unit) {
        val hadPermission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            checkAppUsagePermissionForQ(context)
        } else {
            checkAppUsagePermissionBeforeQ(context)
        }
        if (hadPermission) {
            //授权完成
            permissionGrantListener.invoke(true)
            //上传数据
            val pathList =
                AppConfigUtil.getValidCountrysPaths()
            saveS2SInfo(context, pathList)
        } else {
            //授权失败
            permissionGrantListener.invoke(false)
        }
    }

    /**
     * 针对Android Q 以下版本，判断是否拥有使用统计权限
     * 如果在最近1个小时内没有使用记录，判断为没权限
     *
     * @param context Application
     * @return Boolean true有权限，false没权限
     */
    fun checkAppUsagePermissionBeforeQ(context: Application): Boolean {
        val manager = context.getSystemService(Context.USAGE_STATS_SERVICE) as UsageStatsManager
        val currentTime = System.currentTimeMillis()
        val stats: List<UsageStats> = manager.queryUsageStats(
            UsageStatsManager.INTERVAL_DAILY,
            currentTime - 60 * 60 * 1000,
            currentTime
        )
        if (stats.isEmpty()) {
            return false
        }
        return true
    }

    /**
     * 针对Android Q 以上版本，判断是否拥有使用统计权限
     * 如果在最近1个小时内没有使用记录，判断为没权限
     *
     * @param context Application
     * @return Boolean
     */
    @RequiresApi(Build.VERSION_CODES.Q)
    fun checkAppUsagePermissionForQ(context: Application): Boolean {
        val appOpsManager: AppOpsManager =
            context.getSystemService(AppCompatActivity.APP_OPS_SERVICE) as AppOpsManager
        val mode = appOpsManager.unsafeCheckOpNoThrow(
            AppOpsManager.OPSTR_GET_USAGE_STATS,
            Process.myUid(),
            context.packageName
        )
        return (mode == AppOpsManager.MODE_ALLOWED)
    }

    /**
     * 跳转使用统计权限页
     *
     * @param context 上下文
     */
    fun startToUsageStatsPermissionSettingPage(context: Context) {
        val intent = Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS)
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        context.startActivity(intent)
    }

    /**
     * 查询配置统计列表
     * 默认最近7天
     *
     * @param context Application
     */
    fun queryConfigurationStatsList(context: Application): List<ParamConfigurationStats> {
        //默认最近7天
        val differTime = DIFFER_DAY_TIME_MILLIS * mFetchDays
        val endTime = System.currentTimeMillis()
        val startTime = endTime - differTime
        println("查询配置统计列表: startTime: $startTime  endTime: $endTime")

        //获取统计信息
        val usageStatsManager =
            context.getSystemService(AppCompatActivity.USAGE_STATS_SERVICE) as UsageStatsManager
        val usageStatsResultList = usageStatsManager.queryConfigurations(
            UsageStatsManager.INTERVAL_BEST,
            startTime,
            endTime
        )

        //组装回传参数
        val dataList = mutableListOf<ParamConfigurationStats>()
        for (usageStats in usageStatsResultList) {
            dataList.add(
                ParamConfigurationStats(
                    firstTimeStamp = usageStats.firstTimeStamp,
                    lastTimeStamp = usageStats.lastTimeStamp,
                    lastTimeActive = usageStats.lastTimeActive,
                    totalTimeActive = usageStats.totalTimeActive,
                    activationCount = usageStats.activationCount
                )
            )
        }
        println("查询配置统计列表:${dataList.size}")
        return dataList
    }

    /**
     * 查询事件统计列表
     * 默认最近7天
     *
     * @param context Application
     */
    fun queryEventStatsList(context: Application): List<ParamEventStats> {
        //默认最近7天
        val differTime = DIFFER_DAY_TIME_MILLIS * mFetchDays
        val endTime = System.currentTimeMillis()
        val startTime = endTime - differTime
        println("查询事件统计列表: startTime: $startTime  endTime: $endTime")

        //获取统计信息
        val usageStatsManager =
            context.getSystemService(AppCompatActivity.USAGE_STATS_SERVICE) as UsageStatsManager
        val usageStatsResultList = usageStatsManager.queryEvents(
            startTime,
            endTime
        )

        //组装回传参数
        val dataList = mutableListOf<ParamEventStats>()
        while (usageStatsResultList.hasNextEvent()) {
            val event = UsageEvents.Event()
            if (usageStatsResultList.getNextEvent(event)) {
                dataList.add(
                    ParamEventStats(
                        packageName = event.packageName,
                        className = event.className,
                        timeStamp = event.timeStamp,
                        eventType = event.eventType
                    )
                )
            }
        }
        println("查询事件统计列表:${dataList.size}")
        return dataList
    }

    /**
     * 查询使用统计列表
     * 默认最近7天
     *
     * @param context Application
     */
    fun queryUsageStatsList(context: Application): List<ParamUsageStats> {
        //默认最近7天
        val differTime = DIFFER_DAY_TIME_MILLIS * mFetchDays
        val endTime = System.currentTimeMillis()
        val startTime = endTime - differTime
        println("查询使用统计列表: startTime: $startTime  endTime: $endTime")

        //获取统计信息
        val usageStatsManager =
            context.getSystemService(AppCompatActivity.USAGE_STATS_SERVICE) as UsageStatsManager
        val usageStatsResultList = usageStatsManager.queryAndAggregateUsageStats(
            startTime,
            endTime
        )

        //组装回传参数
        val dataList = mutableListOf<ParamUsageStats>()
        usageStatsResultList.forEach { pck, usageStats ->
            //应用的启动次数
            val launchCount = getUsageStatsLaunchCount(usageStats)
            //最后一次显示时间
            val lastTimeVisible =
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) usageStats.lastTimeVisible else 0L
            //前台服务运行的时间
            val totalTimeForegroundServiceUsed =
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) usageStats.totalTimeForegroundServiceUsed else 0L

            dataList.add(
                ParamUsageStats(
                    packageName = usageStats.packageName,
                    firstTimeStamp = usageStats.firstTimeStamp,
                    lastTimeStamp = usageStats.lastTimeStamp,
                    lastTimeUsed = usageStats.lastTimeUsed,
                    totalTimeInForeground = usageStats.totalTimeInForeground,
                    launchCount = launchCount,
                    lastTimeVisible = lastTimeVisible,
                    totalTimeForegroundServiceUsed = totalTimeForegroundServiceUsed
                )
            )
        }
        println("查询使用统计列表:${dataList.size}")
        return dataList
    }

    /**
     * 利用反射，获取UsageStats中统计的应用启动次数
     *
     * @param usageStats UsageStats
     * @return launchCount 启动次数
     */
    @SuppressLint("DiscouragedPrivateApi")
    @Throws(IllegalAccessException::class)
    private fun getUsageStatsLaunchCount(usageStats: UsageStats): Int {
        var field: Field? = null
        try {
            field = usageStats.javaClass.getDeclaredField("mLaunchCount")
        } catch (e: NoSuchFieldException) {
            e.printStackTrace()
        }
        field?.let {
            return it.getInt(usageStats)
        }
        return 0
    }

    /**
     * 查询配置统计列表
     * 默认最近7天
     *
     * @param context Application
     */
    suspend fun getConfigurationStatsList(context: Application): List<ParamConfigurationStats> =
        withContext(Dispatchers.IO)
        {
            queryConfigurationStatsList(context = context)
        }

    /**
     * 查询事件统计列表
     * 默认最近7天
     *
     * @param context Application
     */
    suspend fun getEventStatsList(context: Application): List<ParamEventStats> =
        withContext(Dispatchers.IO)
        {
            queryEventStatsList(context = context)
        }

    /**
     * 查询使用统计列表
     * 默认最近7天
     *
     * @param context Application
     */
    suspend fun getUsageStatsList(context: Application): List<ParamUsageStats> =
        withContext(Dispatchers.IO)
        {
            queryUsageStatsList(context = context)
        }

    /**
     * 保存使用统计 s2s信息
     *
     * @param context Application
     * @param targetUrlList 服务区地址列表
     */
    fun saveS2SInfo(context: Application, targetUrlList: List<String>) {
        mScope.launch(Dispatchers.IO) {
            //获取数据
            val usageStatsList = getUsageStatsList(context)//0
            val eventStatsList = getEventStatsList(context)//1
            val configurationStatsList = getConfigurationStatsList(context)//3

            //组装gzip字符串
            val usageStatsListGzip = (Gson().toJson(usageStatsList)).toGZipString()
            val eventStatsListGzip = (Gson().toJson(eventStatsList)).toGZipString()
            val configurationStatsListGzip = (Gson().toJson(configurationStatsList)).toGZipString()

            //组装参数
            val params = ParamUsageStatsS2S(
                usageStatsListGzip = usageStatsListGzip,
                eventStatsListGzip = eventStatsListGzip,
                configurationStatsListGzip = configurationStatsListGzip
            )

            //过滤回传地区
            val body = Gson().toJson(params).trim()
            val resultTargetUrlList = TimeZoneUtil.covertToRealTargetServers(targetUrlList)
            println("====== $resultTargetUrlList")

            withContext(Dispatchers.Main) {
                //传多国时，里触发多次
                val apiPath = ApiUrl.GARLICLOAN_PATH_USAGE_STATS_S2S
                resultTargetUrlList.forEach { path ->
                    val pathFormat =
                        if (path.endsWith(apiPath)) path else (path + apiPath)
                    HttpHelper.postData(pathFormat, body)
                }
            }
        }
    }
}